#include "drv_touch.h"
#include "bsp_i2c1.h"


/* FocalTech FT6336U 触摸芯片驱动程序 */


/* define */

#define FT_REG_ID           0x01
#define FT_REG_STAT         0x02

#define FT_REG_TP1          0x03
#define FT_REG_TP2          0x09
#define FT_REG_TP3          0x0F
#define FT_REG_TP4          0x15
#define FT_REG_TP5          0x1B

#define FT_REG_CHIP_ID      0xA3	/* chip ID : 0x64 */
#define FT_REG_CHIP_ID2     0x9F    /* chip ID2 : 0x26 */
#define FT_REG_FW_VER       0xA6	/* FW  version */
#define FT_REG_VENDOR_ID    0xA8	/* TP vendor ID */
#define FT_REG_POINT_RATE   0x88	/* report rate */

/* FT6236 部分值定义 */
#define FT_EVT_TOUCH_MASK       0xC0
#define FT_EVT_TOUCH_DOWN       0x00
#define FT_EVT_TOUCH_UP         0x01
#define FT_EVT_TOUCH_CONTACT    0x02
#define FT_EVT_TOUCH_RESERVED   0x03

#define ft_iic_start()              bsp_i2c1_start()
#define ft_iic_stop()               bsp_i2c1_stop()
#define ft_iic_wait_ack()           bsp_i2c1_wait_ack()
#define ft_iic_ack()                bsp_i2c1_ack()
#define ft_iic_noack()              bsp_i2c1_noack()

#define ft_iic_write_byte(x)        bsp_i2c1_write_byte(x)
#define ft_iic_read_byte()          bsp_i2c1_read_byte()
#define ft_iic_read_byte_noack()    bsp_i2c1_read_byte_noack()
#define ft_iic_read_byte_ack()      bsp_i2c1_read_byte_ack()

#define ft_iic_lock()               bsp_i2c1_lock()
#define ft_iic_unlock()             bsp_i2c1_unlock()


#define FT_IIC_ADDR                 0x70

#pragma pack(1)
typedef struct 
{
    uint16_t event : 2;
    uint16_t null1 : 2;
    uint16_t posx : 12;

    uint16_t id : 4;
    uint16_t posy : 12;

    uint8_t weight;
    uint8_t misc : 4;
    uint8_t null2 : 4;

} _ft_tp_t ;
#pragma pack()


/* static var */

static const _drv_touch_info_t ft_info_t = 
{
    .name = "FT6336U",
    .width = 480,
    .height = 320,
    .id = 0x6426,
};


/* static func */

/**
 * @brief FT6336读取寄存器内容
 * 
 * @param reg 寄存器
 * @param buff 缓存
 * @param size 读取大小
 */
static void ft_read(uint8_t reg, uint8_t *buff, uint8_t size)
{
    uint8_t i;

    ft_iic_lock();
    ft_iic_start();

    ft_iic_write_byte(FT_IIC_ADDR);
    ft_iic_wait_ack();

    ft_iic_write_byte(reg);
    ft_iic_wait_ack();

    ft_iic_start();
    ft_iic_write_byte(FT_IIC_ADDR + 0x01);
    ft_iic_wait_ack();

    for (i = 0; i < (size-1); i++)
    {
        buff[i] = ft_iic_read_byte();
        ft_iic_ack();
    }

    buff[i] = ft_iic_read_byte();
    ft_iic_noack();

    ft_iic_stop();
    ft_iic_unlock();
}

/**
 * @brief 读取ID (0x6426)
 * 
 * @return uint16_t 
 */
static uint16_t ft_read_id(void)
{
    uint16_t id = 0;
    uint8_t tmp;

    ft_read(FT_REG_CHIP_ID, &tmp, 1);
    id = (uint16_t)(tmp << 8);

    ft_read(FT_REG_CHIP_ID2, &tmp, 1);
    id |= tmp;

    return id;
}

/**
 * @brief 初始化
 * 
 * @return int 
 */
static int ft_init(void)
{
    uint16_t id;

    bsp_i2c1_init();

    id = ft_read_id();
    if (id != ft_info_t.id)
    {
        printf("FT6336 read ID(0x%04X:0x%04X) fail\r\n", ft_info_t.id, id);
        return -1;
    }

    return 0;
}

/**
 * @brief 触点扫描
 * 
 * @param pos 
 * @return int 
 */
static int ft_scan(_drv_touch_point_t *pos)
{
    uint8_t idx;
    // _ft_tp_t tp_t; // 大小端问题不能直接用结构体读取
    uint8_t buff[4];
    uint8_t sta;

    if (pos == NULL) return -1;

    pos->cnt = 1;   // 最多支持两触点

    for (idx = 0; idx < pos->cnt; idx++)
    {
        if (idx >= TOUCH_POINT_MAX) break;

        pos->point[idx].sta = TOUCH_STA_NONE;

        ft_read(FT_REG_TP1 + idx * 6, buff, sizeof(buff));

        /* for debug */
    #if 0
        printf("bf: ");
        for (uint8_t i = 0; i < sizeof(buff); i++)
        {
            printf("0x%02X, ", buff[i]);
        }
        printf("\r\n");
    #endif

        /* 触摸状态 */
        sta = buff[0] >> 6;
        switch (sta)
        {
        case FT_EVT_TOUCH_DOWN: pos->point[idx].sta = TOUCH_STA_DOWN; break;
        case FT_EVT_TOUCH_UP: pos->point[idx].sta = TOUCH_STA_UP; break;
        case FT_EVT_TOUCH_CONTACT: pos->point[idx].sta = TOUCH_STA_DOWN; break;
        default:
            break;
        }

        /* 触摸坐标 */
    #if 1
        /* 横屏 */
        pos->point[idx].x = ft_info_t.width - ((buff[2] & 0x0F)<<8|buff[3]);
        pos->point[idx].y = (buff[0] & 0x0F)<<8 | buff[1];
        
    #else
        /* 竖屏 */
        pos->point[idx].x = (buff[0] & 0x0F)<<8 | buff[1];
        pos->point[idx].y = (buff[2] & 0x0F)<<8 | buff[3];
    #endif

    }

    return 0;
}

/**
 * @brief 获取信息
 * 
 * @param info 
 * @return int 
 */
static int ft_get_info(_drv_touch_info_t *info)
{
    if (info == NULL) return -1;

    memcpy(info, &ft_info_t, sizeof(_drv_touch_info_t));

    return 0;
}


/* export var */

const _drv_touch_opt_t touch_opt_ft6336_t = 
{
    .init = ft_init,
    .scan = ft_scan,
    .get_info = ft_get_info,
};



